package com.gitee.wsl.android.net

import android.app.Service
import android.content.Intent
import android.os.Binder
import android.os.Bundle
import android.os.IBinder
import java.io.IOException
import java.io.InputStream
import java.net.InetSocketAddress
import java.net.Socket
import java.net.SocketAddress
import java.nio.ByteBuffer
import java.util.concurrent.Executors


abstract class ConnectService<REQUEST: BaseRequest,RESPONSE: BaseResponse> : Service() {
    /** Socket相关，IP及端口号  */
    private var ip = "192.168.1.110"
    private var port = 2050
    private var wait = 5000
    private var connect: ByteArray? = ByteArray(0)
    private var mSocket: Socket? = null
    private var rxThread: Thread? = null
    private val mExecutor = Executors.newSingleThreadExecutor()
    private val mBinder: ConnectBinder = ConnectBinder()

    internal inner class ConnectBinder : Binder() {
        fun setUpSocketConfigure(data: Bundle) {
            getConfigure(data)
        }

        fun sendMessage(request: REQUEST) {
            val runnable = wrapperRunnable(request)
            mExecutor.execute(runnable)
        }

        val service: ConnectService<REQUEST, RESPONSE>
            get() = this@ConnectService
    }

    override fun onBind(intent: Intent): IBinder {
        return mBinder
    }

    private fun getConfigure(data: Bundle) {
        ip = data.getString("IP", "192.168.1.110")
        port = data.getInt("PORT", 2050)
        wait = data.getInt("WAIT", 5000)
        connect = data.getByteArray("ConnectData")
    }

    @Throws(IOException::class)
    fun setUpConnection() {
        stopExistSocket()
        createSocket()
        startRxThread()
    }

    @Throws(IOException::class)
    private fun stopExistSocket() {
        if (mSocket != null) {
            mSocket = try {
                mSocket!!.close()
                null
            } catch (e: IOException) {
                e.printStackTrace()
                throw e
            }
        }
    }

    @Throws(IOException::class)
    private fun createSocket() {
        val sa: SocketAddress = InetSocketAddress(ip, port)
        mSocket = Socket()
        try {
            //设置信息及超时时间
            mSocket!!.connect(sa, wait)
            val isConnect = mSocket!!.isConnected
            mSocket!!.keepAlive = isConnect
        } catch (e: IOException) {
            mSocket = null
            throw e
        }
    }

    private fun startRxThread() {
        if (rxThread == null || !rxThread!!.isAlive) {
            rxThread = initReceiveThread()
            rxThread!!.start()
        }
    }

    //发送信息
    @Throws(IOException::class)
    fun doSent(data: ByteArray?) {
        if (mSocket == null) {
            setUpConnection()
            writeDataToStream(connect)
        }
        writeDataToStream(data)
    }

    @Throws(IOException::class)
    private fun writeDataToStream(data: ByteArray?) {
        try {
            val os = mSocket!!.getOutputStream()
            os.write(data)
            os.flush()
        } catch (e: IOException) {
            setUpConnection()
            writeDataToStream(connect)
            reSendData(data)
        }
    }

    @Throws(IOException::class)
    private fun reSendData(data: ByteArray?) {
        if (mSocket != null) {
            try {
                val os = mSocket!!.getOutputStream()
                os.write(data)
                os.flush()
            } catch (e: IOException) {
                e.printStackTrace()
                throw e
            }
        }
    }

    private fun wrapperRunnable(request: REQUEST): Runnable {
        return Runnable {
            try {
                doSent(request.data)
            } catch (e: IOException) {
                e.printStackTrace()
                onPostMessageListener!!.onPostError(request.requestMsgType)
            }
        }
    }

    //接受线程
    private fun initReceiveThread(): Thread {
        return Thread {
            try {
                var `is`: InputStream
                while (mSocket != null) {
                    `is` = mSocket!!.getInputStream()
                    val ackbuf = ByteArray(4) //消息号
                    val serialbuf = ByteArray(4) //流水号
                    val lenbuf = ByteArray(4) //长度
                    var datasbuf: ByteArray //数据
                    val ackrs = `is`.read(ackbuf, 0, 4)
                    if (ackrs < 0) {
                        Thread.sleep(1000)
                        continue
                    }
                    `is`.read(serialbuf, 0, 4)
                    `is`.read(lenbuf, 0, 4)
                    val len = ByteBuffer.wrap(lenbuf, 0, 4).int //长度
                    datasbuf = ByteArray(len)
                    `is`.read(datasbuf, 0, len)
                    val response = createInitResponse()
                    response.responseMsgType = ByteBuffer.wrap(ackbuf, 0, 4).int
                    response.serialNumber = ByteBuffer.wrap(serialbuf, 0, 4).int
                    response.data = datasbuf
                    onPostMessageListener!!.onPostResponse(response)
                }
            } catch (e: IOException) {
                e.printStackTrace()
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }

    abstract fun createInitResponse():RESPONSE

    private var onPostMessageListener: OnPostMessageListener<RESPONSE>? = null
    fun setOnPostMessageListener(onPostMessageListener: OnPostMessageListener<RESPONSE>) {
        this.onPostMessageListener = onPostMessageListener
    }

}

interface OnPostMessageListener<RESPONSE: BaseResponse> {
    fun onPostError(typeId: Int)
    fun onPostResponse(response: RESPONSE)
}